package org.zy;

import org.apache.commons.lang3.time.DateUtils;

import java.text.ParseException;
import java.util.*;

/**
 * 自动排班
 */
public class AutoJobScheduling {

    public void test() throws ParseException {
        String[] employees = new String[]{"Lily", "Lucy", "Jack"};
        int shifts = 1;
        List<Holiday> holidays = new ArrayList<>();
        holidays.add(new Holiday("2023-09-29", "2023-10-06", "国庆节", HolidayType.REST));
        holidays.add(new Holiday("2023-10-07", "2023-10-08", "国庆节", HolidayType.WORK));
        Date start = DateUtil.parse("2023-10-01", "yyyy-MM-dd");
        Date end = DateUtil.parse("2023-10-31", "yyyy-MM-dd");
        exec(employees, shifts, holidays, start, end);
    }


    /**
     * 自动排班
     *
     * @param employees 待排班人员ID，属于一个组，轮流值班
     * @param shifts    每日班次（1-3班）
     * @param start     排班开始日期(包含）
     * @param end       排班结束日期(包含）
     */
    public List<SchedulingItem> exec(String[] employees, int shifts, List<Holiday> holidays, Date start, Date end) {
        String[] resetedEmployees = reset(employees);
        int len = employees.length;
        List<Date> workDays = getWorkDays(holidays, start, end);
        List<SchedulingItem> list = new ArrayList<>();
        int index = 0;
        for (Date day : workDays) {
            for (int i = 0; i < shifts; i++) {
                SchedulingItem item = SchedulingItem.builder()
                        .day(day)
                        .shift(i)
                        .employeeId(resetedEmployees[index % len])
                        .build();
                list.add(item);
                index++;
            }
        }
        list.forEach(System.out::println);
        return list;
    }

    public List<Date> getWorkDays(List<Holiday> holidays, Date start, Date end) {
        List<Date> list = new ArrayList<>();
        Map<Date, HolidayType> holidayMap = toHolidayMap(holidays);
        Date today = start;
        while (!today.after(end)) {
            if (!holidayMap.containsKey(today)) {
                if (!DateUtil.isWeekend(today)) {
                    list.add(today);
                }
            } else if (holidayMap.get(today) == HolidayType.WORK) {
                list.add(today);
            }
            today = DateUtils.addDays(today, 1);
        }
        return list;
    }

    public Map<Date, HolidayType> toHolidayMap(List<Holiday> holidays) {
        Map<Date, HolidayType> map = new HashMap<>();

        for (Holiday holiday : holidays) {
            Date start = holiday.getStart();
            Date end = holiday.getEnd();
            while (!start.after(end)) {
                map.put(start, holiday.getType());
                start = DateUtils.addDays(start, 1);
            }
        }
        return map;
    }

    /**
     * 打乱人员顺序，保证公平
     *
     * @param employees
     * @return
     */
    public String[] reset(String[] employees) {
        List<String> list = new LinkedList<>();
        for (int i = 0; i < employees.length; i++) {
            list.add(employees[i]);
        }
        Random ra = new Random();
        int len = employees.length;
        String[] ids = new String[len];
        for (int i = 0; i < len; i++) {
            int index = ra.nextInt(list.size());
            ids[i] = list.remove(index);
        }
        return ids;
    }

}
